//      ml_data.h
//      
//      Copyright 2012 tqlong <tqlong@espada>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.

#ifndef MACHINE_LEARNING_DATA_H
#define MACHINE_LEARNING_DATA_H

#include "stl_helper.h"
#include "ublas_helper.h"

template <typename V, typename M>
class DataTable
{
 public:
  typedef V x_t;
  typedef M data_t;

  data_t& data() { return data_; }
  vec_t& label() { return label_; }
  x_t x(int i) const { return row(data_, i); }
  double y(int i) const { return label_(i); }

  void input_from_list(const std::vector<sparse_vec_t>& d, int dim) 
  {
    int n = sz(d);
    data_ = data_t(n, dim);
    for (int i = 0; i < n; i++) row(data_, i) = subvector(d[i], 0, dim);
    dim_ = dim;
  }

  void set_label(const std::vector<double>& l) 
  {
    int n = sz(l);
    label_ = vec_t(n);
    for (int i = 0; i < n; i++) label_(i) = l[i];
  }

  int size() const
  {
    return data_.size1();
  }
  
  int dim() const 
  {
    return dim_;
  }
 protected:
  data_t data_;
  vec_t label_;
  int dim_;
};

class DataReader
{
 public:
  template <typename DATA> 
  static void read_libsvm(const std::string& inFile, DATA& D, bool bias=false) {
    // scan file to get allocation information
    bool has_label = false;
    int max_idx = 0;
    int n_data = 0;
    {
      FileAccessRead(in, inFile);
      while(!in.eof()) {
	FileAccessLine(in, line);
	str_vec_t tokens;
	boost::split(tokens, line, boost::is_any_of("\t :"), boost::token_compress_on);
	int n_token = sz(tokens);

	if (n_token <= 1) continue;

	int start = 0;
	if (n_token % 2 == 1) has_label = true;
	start = 1;

	for (int i = start; i < n_token; i += 2) {
	  int idx = s2<int>(tokens[i]);
	  //double val = s2<double>(tokens[i+1]);
	  if (idx > max_idx) max_idx = idx;
	}

	n_data++;
      }
    }
    MSG("n_data=" << n_data << " max_idx=" << max_idx);

    D.data().resize(n_data, bias ? max_idx+1:max_idx, false);
    FileAccessRead(in, inFile);
    while(!in.eof()) {
      FileAccessLine(in, line);
      str_vec_t tokens;
      boost::split(tokens, line, boost::is_any_of("\t :"), boost::token_compress_on);
      int n_token = sz(tokens);
      
      if (n_token <= 1) continue;
      
      int start = 0;
      if (n_token % 2 == 1) has_label = true;
      start = 1;
      
      for (int i = start; i < n_token; i += 2) {
	int idx = s2<int>(tokens[i]);
	double val = s2<double>(tokens[i+1]);
	D.data()(n_data, bias ? idx : idx-1) = val;
      }

      n_data++;
    }
    
    /*
    FileAccessRead(in, inFile);
    
    std::vector<double> label;
    std::vector<sparse_vec_t> x;
    int max_idx = -1;
    while (!in.eof()) {
      FileAccessLineSplit(in, line, tokens, "\t :");
      int n_token = sz(tokens);
      //MSG("sz(tokens)=" << n_token);

      if (n_token <= 1) continue; // skip empty line
      
      double l = 0;
      int start = 0;
      if (n_token % 2 == 1) {
	l = s2<double>(tokens[0]);
	start = 1;
      }
      label.pb(l);

      x.pb(sparse_vec_t(100000000));
      sparse_vec_t& v = x.back();
      if (bias) v.pb(0, 1);
      for (int i = start; i < n_token; i+=2) { 
	int idx = s2<int>(tokens[i]);
	double val = s2<double>(tokens[i+1]);
	v.pb(bias ? idx : idx-1, val);
	if (idx > max_idx) max_idx = idx;
      }      
    }

    data.input_from_list(x, bias? max_idx+1 : max_idx);
    data.set_label(label);
    */
  }
};

#endif
